<?php
declare (strict_types = 1);

namespace security\think6;

use app\admin\model\AdminModel;
use security\exception\UnAuthorizationException;
use think\facade\Config;
use think\facade\Cookie;
use think\facade\Session;

class TPAuthenticateMiddleware {

    /**
     * @var \think\Request
     */
    private $request = null;
    
    /**
     * 处理请求
     * @param \think\Request $request
     * @param \Closure       $next
     * @return Response
     */
    public function handle($request, \Closure $next) {
        $this->request = $request;
        if($this->needLogin()) {
            if($request->isAjax()) {
                throw new UnAuthorizationException();
            } else {
                $url = $request->url(true);
                $path = Config::get('security.login_path', '');
                return redirect($path.'?redirect='.urlencode($url));
            }
        }
        return $next($request);
    }

    private function needLogin() {
        $app = app('http')->getName();
        $controller = $this->request->controller(true);
        $action = $this->request->action(true);
        $path = implode(DS, [$app, $controller, $action]);
        // 不需要登录方法
        $whiteList = Config::get('security.white_list', []);
        if(in_array($path, $whiteList)) return false;
        // 需要登录检查是否有登录信息
        $authenticate = $this->getLoginUserId();
        if(empty($authenticate)) return true;
        return false;
    }

    private function getLoginUserId() {
        // 当前会话
        if(Session::has(Config::get('security.session_key'))) {
            return Session::get(Config::get('security.session_key'));
        }
        // 保持会话
        if(Cookie::has(Config::get('security.cookie_key'))) {
            $login = Cookie::get(Config::get('security.cookie_key'));
            list($id, $keeptime, $expiretime, $key) = explode('|', $login);
            if(empty($id) || empty($keeptime) || empty($expiretime) || empty($key)) return null;
            if (time() > $expiretime) return null;
            $admin = (new AdminModel())->field('id, login_token, last_login_ip')->find($id);
            if(empty($admin)) return null;
            if($admin['last_login_ip'] != request()->ip()) return null;
            $checkKey = md5(md5($id) . md5($keeptime) . md5($expiretime) . $admin['login_token'] . Config::get('security.cookie_token', ''));
            if ($key != $checkKey) return null;
            $authenticate = [
                'id' => $admin['id']
            ];
            $cache = json_encode($authenticate, JSON_UNESCAPED_UNICODE);
            Session::set(Config::get('security.session_key'), $cache);
            return $cache;
        }
        return null;
    }

}
